<?php

namespace app\common\model\base;

use app\common\exception\ExceptionEmun;
use app\common\exception\SystemException;
use app\common\model\Admin;
use app\common\token\token;
use app\common\traits\ModelTrait;
use think\db\exception\DataNotFoundException;
use think\db\exception\ModelNotFoundException;
use think\Model;
use think\model\concern\SoftDelete;
use think\model\Pivot;

/**
 * Class Model
 * @package think
 * @mixin \think\db\BaseQuery
 * @method void onAfterRead(Model $model) static after_read事件定义
 * @method void onAfterInsert(Model $model) static after_insert事件定义
 * @method void onAfterUpdate(Model $model) static after_update事件定义
 * @method void onAfterWrite(Model $model) static after_write事件定义
 * @method mixed onBeforeDelete(Model $model) static before_write事件定义
 * @method void onAfterDelete(Model $model) static after_delete事件定义
 * @method void onBeforeRestore(Model $model) static before_restore事件定义
 * @method void onAfterRestore(Model $model) static after_restore事件定义
 */
class BaseModel extends Model
{
    use SoftDelete;
    use ModelTrait;

    /**
     * 状态配置
     */
    const STATUS_ONLINE = 1;
    const STATUS_OFFLINE = 2;
    const STATUS_MAPS = [
        self::STATUS_ONLINE => '启用',
        self::STATUS_OFFLINE => '禁用',
    ];


    //状态文字映射
    protected $deleteTime = 'delete_time';
    //多对多关联隐藏字段
    protected $pivotHiddenField = [
        'pivot', 'delete_time', 'creater_id', 'updater_id', 'create_time', 'update_time', 'status', 'remark'
    ];

    public function __construct($data = [])
    {
        parent::__construct($data);
        $this->autoWriteTimestamp = true;
        $this->deleteTime = 'delete_time';
        $this->defaultSoftDelete = 0;
        $this->hidden = ['delete_time','updater_id'];

    }

    /**
     * 初始化
     */
    protected static function init()
    {
        parent::init();
    }

    public static function onBeforeWrite($data)
    {
        $data['delete_time'] = 0;
        return TRUE;
    }

    /**
     * 获取列表
     * @return mixed|Model|Pivot|null
     * @throws DbException
     */
    public function getList($param)
    {
        $where = $this->getBaseWhere($param);
        $param['page'] = !empty($param['page']) ? $param['page'] : 1;
        $param['limit'] = !empty($param['limit']) ? $param['limit'] : 15;
        $data = static::where($where)
                      ->field($this->baseField)
                      ->page($param['page'], $param['limit'])
                      ->select();
        return $data;
    }

    /**
     * 基础的where,所有查询都应以此为查询条件
     * @return mixed
     */
    public function getBaseWhere($param = [], $alias = '')
    {
        if (!empty($alias)) {
            $alias = strpos($alias, '.') === FALSE ? $alias . "." : $alias;
        }

        $user = Token::instance()->getUserInfo();
        $where = [];
        if (!empty($param['personal'])) {
            $where[] = [$alias . 'creater_id', '=', $user[$user->getPk()]];
        }
        if (!empty($param['creater_id'])) {
            if (is_array($param['creater_id'])) {
                $where[] = [$alias . 'creater_id', 'in', $param['creater_id']];
            } else {
                $where[] = [$alias . 'creater_id', '=', $param['creater_id']];
            }
        }
        return $where;
    }

    /**
     * 获取统计数量
     * @param $param
     * @return mixed|Model|Pivot|null
     */
    public function getCount($param)
    {
        $where = $this->getBaseWhere($param);
        $data = static::where($where)->count();
        return $data;
    }

    /**
     * 根据ID获取值
     * @param string $id
     * @return BaseModel|null
     */
    public function getByID($id = '')
    {
        $data = static::field($this->baseField)->find($id);
        return $data;
    }

    /**
     * [createData 新建]
     * @linchuangbin
     * @DateTime  2017-02-10T21:19:06+0800
     * @param array $param [description]
     * @return bool [array]                         [description]
     * @throws Exception
     */
    public function createData($param)
    {
        try {
            $this->data($param)->save();
            return TRUE;
        }
        catch (Exception $e) {
            throw $e;
        }
    }

    /**
     * [updateDataById 编辑]
     * @linchuangbin
     * @DateTime  2017-02-10T21:24:49+0800
     * @param $param
     * @param $id
     * @return bool [type]                          [description]
     * @throws Exception
     */
    public function updateByID($param, $id)
    {
        $id = $param[$this->getPk()] ?? $id;
        $checkData = $this->find($id);
        if (!$checkData) {
            ExceptionEmun::throwException(SystemException::INVALID_PARAMETER);
        }
        // 验证
        try {
            $checkData->save($param);
            return TRUE;
        }
        catch (Exception $e) {
            throw $e;
        }
    }

    /**
     * [delDataById 根据id删除数据]
     * @linchuangbin
     * @DateTime  2017-02-11T20:57:55+0800
     * @param string $id [主键]
     * @param boolean $delSon [是否删除子孙数据]
     * @return bool [type]                           [description]
     * @throws Exception
     */
    public function delByID($id = '', $delSon = FALSE)
    {
        $this->startTrans();
        try {
            static::destroy($id);
            if ($delSon && is_numeric($id)) {
                // 删除子孙
                $childIds = $this->getAllChild($id);
                if ($childIds) {
                    $this->where($this->getPk(), 'in', $childIds)->delete();
                }
            }
            $this->commit();
            return TRUE;
        }
        catch (Exception $e) {
            throw $e;
            $this->rollback();
            return FALSE;
        }
    }

    /**
     * 获取所有子孙
     * @param $id
     * @param array $data
     * @return array
     */
    public function getAllChild($id, &$data = [])
    {
        $map['pid'] = $id;
        $childIds = $this->where($map)->column($this->getPk());
        if (!empty($childIds)) {
            foreach ($childIds as $v) {
                $data[] = $v;
                $this->getAllChild($v, $data);
            }
        }
        return $data;
    }

    /**
     * [delDatas 批量删除数据]
     * @linchuangbin
     * @DateTime  2017-02-11T20:59:34+0800
     * @param array $ids [主键数组]
     * @param boolean $delSon [是否删除子孙数据]
     * @return bool [type]                          [description]
     * @throws Exception
     */
    public function delByIDs($ids = [], $delSon = FALSE)
    {
        $this->startTrans();
        if (empty($ids)) {
            ExceptionEmun::throwException(SystemException::INVALID_PARAMETER);
        }

        // 查找所有子元素
        if ($delSon) {
            foreach ($ids as $k => $v) {
                if (!is_numeric($v)) {
                    continue;
                }
                $childIds = $this->getAllChild($v);
                foreach ($childIds as $key => $value) {
                    $ids[] = $value;
                }
            }
            $ids = array_unique($ids);
        }
        try {
            static::destroy($ids);
            $this->commit();
            return TRUE;
        }
        catch (Exception $e) {
            throw $e;
        }

    }

    /**
     * [enableDatas 批量启用、禁用]
     * @AuthorHTL
     * @DateTime  2017-02-11T21:01:58+0800
     * @param array $ids [主键数组]
     * @param integer $status [状态1启用0禁用]
     * @param bool $delSon
     * @return bool [type]                           [description]
     * @throws Exception
     */
    public function enableByIDs($ids = [], $status = 1, $delSon = FALSE)
    {
        $this->startTrans();
        if (empty($ids)) {
            ExceptionEmun::throwException(SystemException::INVALID_PARAMETER);
        }
        // 查找所有子元素
        if ($delSon && $status === '0') {
            foreach ($ids as $k => $v) {
                $childIds = $this->getAllChild($v);
                foreach ($childIds as $key => $value) {
                    $ids[] = $value;
                }
            }
            $ids = array_unique($ids);
        }
        try {
            $this->where($this->getPk(), 'in', $ids)
                 ->save(['status' => $status]);
            $this->commit();
            return TRUE;
        }
        catch (Exception $e) {
            throw $e;
        }
    }

    /**
     * @param $field
     * @param $value
     * @return array|PDOStatement|string|Model|null
     * @throws DbException
     * @throws DataNotFoundException
     * @throws ModelNotFoundException
     */
    public function getByField($field, $value)
    {
        $where = [
            [$field, '=', $value],
        ];
        $ret = static::where($where)
                     ->field($this->baseField)
                     ->find();
        return $ret;
    }

    public function creater()
    {
        return $this->belongsTo(Admin::class, 'creater_id', Admin::instance()->getPk())
                    ->field([
                        'create_time',
                        'update_time',
                        'username',
                        'realname',
                        Admin::instance()->getPk() => 'id',
                        Admin::instance()->getPk(),
                    ]);
    }

    protected function prefixImgUrl($value, $data)
    {
        $final_url = $value;
        if ($data['from'] == 1) {
            $final_url = sprintf('%s/images/%s', config('setting.img_prefix'), $value);
            $final_url = str_replace('//', '/', $final_url);
        }
        return $final_url;
    }

}
